﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common;
using System.IO;

namespace Neural
{
    public class SeriesUtils
    {
        private const char NEWLINE_SPLITTER = '\n';
        private const char COMMA_SPLITTER = ',';

        /// <summary>
        /// Normalizes the series file.
        /// </summary>
        /// <param name="inputFilename">Series file name.</param>
        /// <param name="outputFilename">Result file filename.</param>
        public void NormalizeSeries(String inputFilename, String outputFilename)
        {
            if (File.Exists(outputFilename))
            {
                Console.WriteLine("Output file already exists. Please retry after deleting.");

                return;
            }

            List<NormalizationRule> normalizationRules = new List<NormalizationRule>();
            normalizationRules.Add(new NormalizationRule(1, 35000, 5000000)); // in pair money
            normalizationRules.Add(new NormalizationRule(18, 1, 10)); // coefficients
            normalizationRules.Add(new NormalizationRule(18, 0, 1000000)); // money
            normalizationRules.Add(new NormalizationRule(1, 600000, 18000000)); // time before beginning

            Normalizer normalizer = new Normalizer();

            using (StreamReader inputFile = new StreamReader(inputFilename))
            {
                using (StreamWriter outputFile = new StreamWriter(outputFilename, true))
                {
                    String line;

                    // writing file header
                    outputFile.WriteLine(inputFile.ReadLine());

                    while ((line = inputFile.ReadLine()) != null)
                    {
                        outputFile.WriteLine(
                            Convertation.DoubleArrayToString(
                            normalizer.Normalize(Convertation.StringToDoubleArray(line)
                            , normalizationRules)));
                    }
                }
            }
        }

        public void SelectColumn(String inputFilename, Int32 columnIndex)
        {
            FileInfo fileInfo = new FileInfo(inputFilename);
            String fileNameWithoutExtension = fileInfo.DirectoryName + fileInfo;
            String extension = Path.GetExtension(inputFilename);
            Console.WriteLine(fileNameWithoutExtension);
            String outputFilename = String.Format("{0}-col{1}{2}", fileNameWithoutExtension, columnIndex, extension);
            //SelectColumn(inputFilename, outputFilename, columnIndex);
            throw new NotImplementedException();
        }

        /// <summary>
        /// Selects the only column form file by the index and writes it to another file.
        /// </summary>
        /// <param name="inputFilename"></param>
        /// <param name="outputFilename"></param>
        /// <param name="columnIndex"></param>
        public void SelectColumn(String inputFilename, String outputFilename, Int32 columnIndex)
        {
            if (File.Exists(outputFilename))
            {
                Console.WriteLine("Output file already exists. Please retry after deleting.");

                return;
            }

            using (StreamReader inputFile = new StreamReader(inputFilename))
            {
                using (StreamWriter outputFile = new StreamWriter(outputFilename, true))
                {
                    String line;

                    // skipping file header
                    inputFile.ReadLine();

                    while ((line = inputFile.ReadLine()) != null)
                    {
                        Double value = Convertation.StringToDoubleArray(line)[columnIndex];
                        outputFile.WriteLine(value);
                    }
                }
            }
        }

        /// <summary>
        /// Thins the file out. Saves to the output file every thinOutValue's line. (Every second, every third etc.)
        /// Should be better tested!
        /// </summary>
        /// <param name="inputFilename">Input file name.</param>
        /// <param name="outputFilename">Output file name.</param>
        /// <param name="thinOutValue">See the method description.</param>
        public void ThinOutFile(String inputFilename, String outputFilename, Int32 thinOutValue)
        {
            if (File.Exists(outputFilename))
            {
                Console.WriteLine("Output file already exists. Please retry after deleting.");

                return;
            }

            using (StreamReader inputFile = new StreamReader(inputFilename))
            {
                using (StreamWriter outputFile = new StreamWriter(outputFilename, true))
                {
                    String line;
                    Int32 counter = 0;

                    // writing file header
                    outputFile.WriteLine(inputFile.ReadLine());

                    while ((line = inputFile.ReadLine()) != null)
                    {
                        if (counter++ % thinOutValue == 0)
                        {
                            outputFile.WriteLine(line);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Converts the csv file from fracsoft.com to the series file.
        /// Not implemented yet.
        /// </summary>
        /// <param name="inputFilename">Csv file name.</param>
        /// <param name="outputFilename">Series file name.</param>
        public void CsvToSeries(String inputFilename, String outputFilename)
        {
            String[] values = System.IO.File.ReadAllText(inputFilename).Split(NEWLINE_SPLITTER);

            for (int i = 0; i < values.Length; i += 3)
            {
                String[] subvalues = values[i].Split(COMMA_SPLITTER);

                if (subvalues.Length >= 6)
                {
                    Console.WriteLine(subvalues[5]);
                }
            }
        }

        /// <summary>
        /// Creates the training file from all series from given directory.
        /// </summary>
        /// <param name="directory">See description.</param>
        /// <param name="outputFilename">Result filename.</param>
        public void CreateTrainingFile(String directory, String outputFilename)
        {
            String[] filePaths = Directory.GetFiles(directory, "*.txt");
            List<TrainingPair> trainingPairs = new List<TrainingPair>();

            foreach (String filePath in filePaths)
            {
                trainingPairs.AddRange(SeriesToTrainingPairs(filePath));
            }

            if (!trainingPairs.Count.Equals(0))
            {
                Int32 pairsCount = trainingPairs.Count;
                Int32 inputsCount = trainingPairs[0].First.Length;
                Int32 outputCount = trainingPairs[0].Second.Length;

                String header = String.Format("{0} {1} {2}{3}", pairsCount, inputsCount, outputCount, Environment.NewLine);
                System.IO.File.AppendAllText(outputFilename, header);

                foreach (TrainingPair trainingPair in trainingPairs)
                {
                    System.IO.File.AppendAllText(outputFilename, String.Format("{0}{1}", trainingPair.ToString(), Environment.NewLine));
                }
            }
            else
            {
                Console.WriteLine("[SeriesUtils] No training pairs have been generated.");
            }
        }

        public List<TrainingPair> SeriesToTrainingPairs(String filename)
        {
            String path = System.IO.Path.GetDirectoryName(filename);
            String tempFilename1 = path + @"\temp1.txt";
            String tempFilename2 = path + @"\temp2.txt";

            String file = System.IO.Path.GetFileName(filename);
            String outputFilename = path + @"\output\" + file;

            SelectColumn(filename, tempFilename1, 1);
            ThinOutFile(tempFilename1, outputFilename, 6);

            File.Delete(tempFilename1);

            

            return new List<TrainingPair>();
        }
    }
}
